package cn.oowoo.rabbitmq.akc;

import cn.oowoo.rabbitmq.config.RabbitConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

/**
 * @Author ZhangBin
 * @Date 2021/5/7 18:41
 * @Description: 手动确认-消费者
 *
 **/
@Slf4j
public class AckConsumer {




    public static void main(String[] args) throws Exception {
        Connection connection = RabbitConfig.createConnection();
        // 创建消息通道
        Channel channel = connection.createChannel();

        // 声明队列（默认交换机AMQP default，Direct）
        channel.queueDeclare(RabbitConfig.QUEUE_ACK_NAME, false, false, false, null);


        // 创建消费者，并接收消息
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg = new String(body, "UTF-8");
                System.out.println("Received message : '" + msg + "'");
                if(properties != null && properties.getHeaders()!=null){
                    System.out.println("properties="+ properties.getHeaders().get("token"));
                }

                if (msg.contains("拒收")){
                    /**
                     * 拒绝消息
                     *
                     *  void basicNack(long deliveryTag, boolean multiple, boolean requeue)
                     *  requeue：是否重新入队列，true：是；false：直接丢弃。为true的时候会造成消息重复消费，会造成死循环
                     *  一般工作中不会设置重回队列这个属性，我们都是自己去做补偿或者投递到延迟队列里的，然后指定时间去处理即可。
                     */
                    channel.basicReject(envelope.getDeliveryTag(), false);
                    log.info("拒收的消息。。。做特殊业务处理 --> msg={}",msg);
                } else if (msg.contains("异常")){
                    /**
                     * 业务异常情况消息处理逻辑
                     *
                     * void basicNack(long deliveryTag, boolean multiple, boolean requeue)
                     *  requeue：是否重新入队列，true：是；false：直接丢弃,相当于告诉队列可以直接删除掉。为true的时候会造成消息重复消费，会造成死循环
                     *  一般工作中不会设置重回队列这个属性，我们都是自己去做补偿或者投递到延迟队列里的，然后指定时间去处理即可。
                     */
                    channel.basicNack(envelope.getDeliveryTag(), false, false);
                    log.info("异常消息。。。做特殊业务处理 --> msg={}",msg);
                } else {

                    /**
                    * 不管multiple是否设置为true，都会被确认。如果不执行channel.basicAck方法，消息将会一直保存在队列中，等待下次链接的时候继续消费
                    * 当channel关闭后未被确认的消息会从Unacked状态变为Ready状态，当channel再次打开再次消费之后，消息会重新变为Unacked状态
                    * void basicAck(long deliveryTag, boolean multiple)
                    * */
                    channel.basicAck(envelope.getDeliveryTag(), true);
                    log.info("一条消息被消费 --> msg={}",msg);
                }
            }
        };
        /**
         * autoAck= false :关闭自动确认，也就是开启手动确认
         * 开始获取消息，注意这里开启了手工应答（关闭自动应答）
         * String basicConsume(String queue, boolean autoAck, Consumer callback)
         *
         */
        channel.basicConsume(RabbitConfig.QUEUE_ACK_NAME, false, consumer);

    }
}


